package com.xingda.packing.dmss.domain;

import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xingda.packing.dmss.common.StorageUtils;
import com.xingda.packing.dmss.enums.*;
import com.xingda.packing.dmss.events.EventCreater;
import com.xingda.packing.dmss.events.dto.EventActionCachePacking;
import com.xingda.packing.dmss.events.dto.EventActionPacking;
import com.xingda.packing.dmss.events.dto.EventActionStorage;
import com.xingda.packing.dmss.minitor.entity.*;
import com.xingda.packing.dmss.minitor.mapper.*;
import com.xingda.packing.dmss.minitor.service.IPkActionService;
import com.xingda.packing.dmss.plc.service.PlcDirectiveService;
import com.xingda.packing.dmss.task.ticket.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 机器人
 */
@Data
@Slf4j
@Component
public class Robot {

    @Resource
    EventCreater eventCreater;
    @Resource
    private PlcDirectiveService plcDirectiveService;
    @Resource
    private PkVisualSenseMapper pkVisualSenseMapper;
    @Resource
    private PkActionMapper pkActionMapper;
    @Resource
    private StorageUtils storageUtils;
    @Resource
    private PkBomMapper pkBomMapper;
    @Resource
    private PkWheelMapper pkWheelMapper;
    @Resource
    private PkAlarmHistoryMapper pkAlarmHistoryMapper;

    @Resource
    private PkTaskMapper pkTaskMapper;
    @Resource
    private PkTaskInfoMapper pkTaskInfoMapper;
    @Resource
    private PkCacheLocationMapper pkCacheLocationMapper;
    @Resource
    private IPkActionService pkActionService;
    @Setter
    @Getter
    private AbstractTaskTicket taskTicket1;
    @Setter
    @Getter
    private AbstractTaskTicket taskTicket2;
    /**
     * 工字轮
     */
    @Getter
    @Setter
    private Wheel wheel1;

    @Getter
    @Setter
    private Wheel wheel2;
    @Getter
    @Setter
    private boolean isLeftWorkStatus = true;
    @Getter
    @Setter
    private boolean isRightWorkStatus = true;

    @Getter
    @Setter
    private boolean cancel1 = false;
    @Getter
    @Setter
    private boolean cancel2 = false;

    @Getter
    @Setter
    private boolean tag1 = false;
    @Getter
    @Setter
    private boolean tag2 = false;
    @Getter
    @Setter
    private boolean tag3 = false;
    @Getter
    @Setter
    private boolean isLeftRobotAlreadyPacking = false;
    @Getter
    @Setter
    private boolean isRightRobotAlreadyPacking = false;
    @Getter
    @Setter
    private boolean isLeftShuntAreaAlreadyPacking = false;


    public void setTagValue(int area, boolean value) {
        if (area == 1) {
            this.tag1 = value;
        } else if (area == 2) {
            this.tag2 = value;
        } else if (area == 3) {
            this.tag3 = value;
        }
    }

    public void setAlreadyPackingStatus(int area, boolean value) {
        if (area == 1) {
            this.isLeftRobotAlreadyPacking = value;
        } else if (area == 2) {
            this.isRightRobotAlreadyPacking = value;
        } else {
            this.isLeftShuntAreaAlreadyPacking = value;
        }
    }

    public boolean getTagValue(int area) {
        if (area == 1) {
            return tag1;
        } else if (area == 2) {
            return tag2;
        } else {
            return tag3;
        }
    }

    public boolean getAlreadyPackingStatus(int area) {
        if (area == 1) {
            return isLeftRobotAlreadyPacking;
        } else if (area == 2) {
            return isRightRobotAlreadyPacking;
        } else {
            return isLeftShuntAreaAlreadyPacking;
        }
    }

    public boolean getWorkStatus(int area) {
        if (area == 1) {
            return isLeftWorkStatus;
        } else {
            return isRightWorkStatus;
        }
    }

    public void checkPackingStatus(int area, String barCode) {
        LambdaQueryWrapper<PkWheel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PkWheel::getBarCode, barCode);
        List<PkWheel> pkWheels = pkWheelMapper.selectList(lambdaQueryWrapper);
        if (!pkWheels.isEmpty()) {
            //判断是否在缓存位
            List<Integer> cacheLocation = pkCacheLocationMapper.selectList(null).stream().map(PkCacheLocation::getWheelId).collect(Collectors.toList());
            if (!cacheLocation.isEmpty()) {
                LambdaQueryWrapper<PkWheel> wrapper = new LambdaQueryWrapper<>();
                wrapper.in(PkWheel::getId, cacheLocation);
                List<PkWheel> pkWheels1 = pkWheelMapper.selectList(wrapper);
                if (pkWheels1.stream().anyMatch(wheel -> wheel.getBarCode().equals(barCode)) && !getAlreadyPackingStatus(area)) {
                    setAlreadyPackingStatus(area, true);
                    setTagValue(area, true);
                    eventCreater.createTriggerAlarm(AlarmTriggerType.WHEEL_ALREADY_PACKING, true, area);
                    eventCreater.createPkEvent(EventType.ALARM, area, "当前轮号在缓存位已经存在");
                }
            }
            //判断是否是当前装箱位
            LambdaQueryWrapper<PkTask> pkTaskLambdaQueryWrapper = new LambdaQueryWrapper<>();
            pkTaskLambdaQueryWrapper.isNull(PkTask::getEndTime);
            List<Integer> packLocation = pkTaskMapper.selectList(pkTaskLambdaQueryWrapper).stream().map(PkTask::getId).collect(Collectors.toList());
            if (!packLocation.isEmpty()) {
                LambdaQueryWrapper<PkTaskInfo> pkTaskInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                pkTaskInfoLambdaQueryWrapper.in(PkTaskInfo::getTaskId, packLocation);
                List<PkTaskInfo> pkTaskInfos = pkTaskInfoMapper.selectList(pkTaskInfoLambdaQueryWrapper);
                if (!pkTaskInfos.isEmpty()) {
                    List<Integer> collect = pkTaskInfos.stream().map(PkTaskInfo::getWheelId).collect(Collectors.toList());
                    LambdaQueryWrapper<PkWheel> wrapper = new LambdaQueryWrapper<>();
                    wrapper.in(PkWheel::getId, collect);
                    List<PkWheel> pkWheels1 = pkWheelMapper.selectList(wrapper);
                    if (pkWheels1.stream().anyMatch(wheel -> wheel.getBarCode().equals(barCode)) && !getAlreadyPackingStatus(area)) {
                        setAlreadyPackingStatus(area, true);
                        setTagValue(area, true);
                        eventCreater.createTriggerAlarm(AlarmTriggerType.WHEEL_ALREADY_PACKING, true, area);
                        eventCreater.createPkEvent(EventType.ALARM, area, "当前轮号在装箱区已经存在");
                    }
                }
            }
        }
    }

    public AbstractTaskTicket getTaskTicket(int area) {
        if (area == 1) {
            return taskTicket1;
        } else {
            return taskTicket2;
        }
    }

    public void setTaskTicket(AbstractTaskTicket ticket, int area) {
        if (area == 1) {
            this.taskTicket1 = ticket;
        } else {
            this.taskTicket2 = ticket;
        }
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void setWorkStatus(boolean value, int area) {
        if (area == 1) {
            isLeftWorkStatus = value;
        } else {
            isRightWorkStatus = value;
        }
    }

    public Wheel getWheel(int area) {
        if (area == 1) {
            return wheel1;
        } else {
            return wheel2;
        }
    }

    /**
     * 是否可下发任务
     *
     * @return 可以下发=true,不可下发=false
     */
    public boolean checkCanAssignTaskTicket(int area) {
        if (area == 1) {
            return taskTicket1 == null || taskTicket1.getState() == TaskState.FINISH;
        } else {
            return taskTicket2 == null || taskTicket2.getState() == TaskState.FINISH;
        }
    }

    /**
     * 下发任务
     *
     * @param taskTicket 任务单
     */
    public void assignTaskTicket(AbstractTaskTicket taskTicket, int area) {
        if (checkCanAssignTaskTicket(area)) {
            if (area == 1) {
                this.taskTicket1 = taskTicket;
            } else {
                this.taskTicket2 = taskTicket;
            }
            log.info("任务单下发成功：任务单类型：{}", taskTicket.getType().getTypeName());
        }
    }

    /**
     * 是否允许下发任务
     */
    public boolean canAssignTask(int area) {
        return plcDirectiveService.canAssignTask(area);
    }

    /**
     * 100位置是否有轮子
     */
    public boolean is100HaveWheel(int area) {
        return plcDirectiveService.isHaveWheel(area);
    }

    /**
     * 获得条形码
     */
    public String getScanWheelNo(int area) {
        return plcDirectiveService.getScanWheelNo(area);
    }

    /**
     * 查询高低轮
     */
    public int getProductTypeToZeroGrab(int area) {
        return plcDirectiveService.getProductTypeToZeroGrab(area);
    }

    /**
     * 下发确认抓取轮子
     *
     * @param area 区域
     */
    public void grabWheel(int area) {
        plcDirectiveService.grabWheel(area);
    }

    /**
     * 抓取缓存位放装箱
     *
     * @param cacheLocationNo 缓存位编号
     * @param boxLocationNo   装箱位编号
     * @param productType     产品类型
     * @param wheelNo         条形码
     */
    public void startCacheGrab(int cacheLocationNo, int boxLocationNo, int productType, String wheelNo, int area) {
        plcDirectiveService.startCacheGrab(cacheLocationNo, boxLocationNo, productType, wheelNo, area);
    }

    /**
     * 抓取起始位放装箱位
     *
     * @param wheelTypeCode 工字轮类型编码(产品类型)
     * @param boxLocationNo 装箱位
     */
    public void startGrab(int wheelTypeCode, int boxLocationNo, int area) {
        plcDirectiveService.startGrab(wheelTypeCode, boxLocationNo, area);
    }

    /**
     * 抓取起始位放缓存位
     *
     * @param wheelTypeCode   工字轮类型编码(产品类型)
     * @param cacheLocationNo 缓存位置编号
     */
    public void startStorage(int wheelTypeCode, int cacheLocationNo, int area) {
        plcDirectiveService.startStorage(wheelTypeCode, cacheLocationNo, area);
    }

    /**
     * 抓取完成
     */
    public boolean isGrabComplete(int area) {
        return plcDirectiveService.isGrabComplete(area);
    }

    /**
     * 重置抓取完成
     */
    public void resetGrabState(int area) {
        plcDirectiveService.resetGrabState(area);
    }

    public void resetStatus(int area) {
        resetGrabState(area);
    }

    /**
     * 码垛完成
     */
    public boolean isPalletizingComplete(int area) {
        return plcDirectiveService.isPalletizingComplete(area);
    }

    public void resetPalletizingState(int area) {
        plcDirectiveService.resetPalletizingState(area);
    }

    /**
     * 机器人是否为空
     */
    public boolean isEmpty(int area) {
        if (area == 1) {
            return Objects.isNull(this.wheel1);
        } else {
            return Objects.isNull(this.wheel2);
        }
    }

    /**
     * 机器人上是否有轮
     */
    public boolean haveWheel(int area) {
        if (area == 1) {
            return Objects.nonNull(this.wheel1);
        } else {
            return Objects.nonNull(this.wheel2);
        }
    }

    public void putWheel(Wheel wheel, int area) {
        if (area == 1) {
            this.wheel1 = wheel;
        } else {
            this.wheel2 = wheel;
        }
        storageUtils.saveWheel(wheel, area);
        log.info("机器人抓轮成功，轮号：{},扭转值：{}", wheel.getBarCode(), wheel.getTorsionValue());
    }

    public void clear(int area) {
        if (area == 1) {
            this.wheel1 = null;
        } else {
            this.wheel2 = null;
        }
        storageUtils.saveWheel(null, area);
        log.info("机器人放轮成功-已清空");
    }

    /**
     * 触发
     */
    @JSONField(serialize = false)
    public boolean isScanSignal(int area) {
        return plcDirectiveService.isScanSignal(area);
    }

    /**
     * 轮号接收完成
     */
    public void receive(int productType, int area) {
        plcDirectiveService.receive(productType, area);
    }

    /**
     * 去起始点(传送带位置)抓取
     */
    public void goZeroGrab(int locationNo, int area) {
        plcDirectiveService.goZeroGrab(locationNo, area);
    }

    /**
     * 获得机器人停止状态，true为停止 false为运行（此处停止只包含上位机的强制停止）
     */
    public boolean getStopStatus(int area) {
        return plcDirectiveService.getRobotStatus(area);
    }

    /**
     * 启动初始化机器人状态
     */
    public void initStatus(int area) {
        Wheel wheel = storageUtils.loadWheel(area);
        if (Objects.nonNull(wheel)) {
            this.putWheel(wheel, area);
        }
        AbstractTaskTicket ticket = storageUtils.loadTaskTicket(area);
        if (ticket != null) {
            if (area == 1) {
                this.setTaskTicket1(ticket);
            } else {
                this.setTaskTicket2(ticket);
            }
        }
    }

    public void createCachePackingEvent(CachePackingTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.CACHE_PALLETIZING, area, WorkAreaType.getByID(area).getTypeName() + ":<br>创建缓存位到装箱位任务");
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void createPackingEvent(PackingTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.PACKING, area, WorkAreaType.getByID(area).getTypeName() + ":<br>创建抓取位放装箱位任务");
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void createScanCodeEvent(ScanCodeTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.SCANCODE, area, WorkAreaType.getByID(area).getTypeName() + ":<br>创建抓取位扫码任务,抓取位置:" + ticket.getLocationNo());
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void createStorageEvent(StorageTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.STORAGE, area, WorkAreaType.getByID(area).getTypeName() + ":<br>创建抓取位放缓存位任务");
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void handleCachePackingEvent(CachePackingTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.CACHE_PALLETIZING, area, WorkAreaType.getByID(area).getTypeName() + ":<br>抓取缓存位：", ticket.getCacheLocationNo(), "，<br>码垛托盘号：", ticket.getProductBoxLocationNo(), "，<br>产品类别：", ticket.getWheel().getVFree2());
        storageUtils.saveTaskTicket(ticket, area);
        EventActionCachePacking actionCachePacking = new EventActionCachePacking();
        actionCachePacking.setTicket(ticket);
        actionCachePacking.setArea(area);
        pkActionService.addPkAction(actionCachePacking);
        //eventCreater.createPkActionCachePacking(ticket, area);
    }

    public void handlePackingEvent(PackingTicket ticket, int boxLocationNo, int area) {
        eventCreater.createPkEvent(EventType.PACKING, area, WorkAreaType.getByID(area).getTypeName() + ":<br>放置托盘号：", boxLocationNo, "，<br>产品类别：", ticket.getWheel().getVFree2());
        storageUtils.saveTaskTicket(ticket, area);
        EventActionPacking actionPacking = new EventActionPacking();
        actionPacking.setTicket(ticket);
        actionPacking.setArea(area);
        pkActionService.addPkAction(actionPacking);
        //eventCreater.createPkActionPacking(ticket, area);
    }

    public void handleScanCodeEvent(ScanCodeTicket ticket, int area) {
        Wheel wheel = getWheel(area);
        eventCreater.createPkEvent(EventType.SCANCODE, area, WorkAreaType.getByID(area).getTypeName() + ":<br>读码完成:", wheel.getBarCode(), "，<br>扭转值：", wheel.getTorsionValue().setScale(2, RoundingMode.HALF_UP).doubleValue(), "，<br>焊点数：", wheel.getSolderJointCount(), "，<br>是否重卷：", wheel.isAnew(), "，<br>产品类别：", wheel.getVFree2(), "，<br>客户：", wheel.getConsumerName());
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void handleStorageEvent(StorageTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.STORAGE, area, WorkAreaType.getByID(area).getTypeName() + ":<br>放置缓存位置号：", ticket.getCacheLocationNo(), "，<br>产品类别：", ticket.getWheel().getVFree2(), "，<br>扭转值：", ticket.getWheel().getTorsionValue());
        storageUtils.saveTaskTicket(ticket, area);
        EventActionStorage actionStorage = new EventActionStorage();
        actionStorage.setTicket(ticket);
        actionStorage.setArea(area);
        pkActionService.addPkAction(actionStorage);
        //eventCreater.createPkActionStorage(ticket, area);
    }

    public void listenerCachePackingEvent(CachePackingTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.CACHE_PALLETIZING, area, WorkAreaType.getByID(area).getTypeName() + ":<br>缓存位到装箱位任务完成");
        storageUtils.saveTaskTicket(ticket, area);
        //eventCreater.createFinishPkAction(ActionType.CACHE_PALLETIZING, area);
        pkActionService.finishPkAction(ActionType.CACHE_PALLETIZING, area);
        setWorkStatus(true, area);
        plcDirectiveService.resetPalletizingState(area);
    }

    public void listenerPackingEvent(PackingTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.PACKING, area, WorkAreaType.getByID(area).getTypeName() + ":<br>抓取位放装箱位任务完成");
        storageUtils.saveTaskTicket(ticket, area);
        //eventCreater.createFinishPkAction(ActionType.PACKING, area);
        pkActionService.finishPkAction(ActionType.PACKING, area);
        setWorkStatus(true, area);
        plcDirectiveService.resetPalletizingState(area);
    }

    public void listenerScanCodeEvent(ScanCodeTicket ticket, int area) {
        eventCreater.createTriggerAlarm(AlarmTriggerType.WHEEL_ERROR_99, false, area);
        eventCreater.createTriggerAlarm(AlarmTriggerType.WHEEL_ERROR_999, false, area);
        eventCreater.createTriggerAlarm(AlarmTriggerType.WHEEL_ERROR_9999, false, area);
        eventCreater.createPkEvent(EventType.SCANCODE, area, WorkAreaType.getByID(area).getTypeName() + ":<br>抓取位扫码任务完成");
        storageUtils.saveTaskTicket(ticket, area);
    }

    public void listenerStorageEvent(StorageTicket ticket, int area) {
        eventCreater.createPkEvent(EventType.STORAGE, area, WorkAreaType.getByID(area).getTypeName() + ":<br>抓取位放缓存位任务完成");
        storageUtils.saveTaskTicket(ticket, area);
        //eventCreater.createFinishPkAction(ActionType.STORAGE, area);
        pkActionService.finishPkAction(ActionType.STORAGE, area);
        setWorkStatus(true, area);
        plcDirectiveService.resetPalletizingState(area);
    }

    public void createAlarmEvent(String content, int area) {
        eventCreater.createPkEvent(EventType.ALARM, area, WorkAreaType.getByID(area).getTypeName() + content);
    }

    public void saveVisualSense(String scanWheelNo, int area) {
        PkVisualSense pkVisualSense = new PkVisualSense();
        pkVisualSense.setArea(area);
        pkVisualSense.setScanWheelNo(scanWheelNo);
        pkVisualSense.setCreateTime(new Date());
        pkVisualSenseMapper.insert(pkVisualSense);
    }

    public void initAlarm(int area) {
        eventCreater.createTriggerAlarm(AlarmTriggerType.NO_PRODUCT_TYPE, false, area);
        eventCreater.createTriggerAlarm(AlarmTriggerType.PRODUCT_TYPE_ERROR, false, area);
        eventCreater.createTriggerAlarm(AlarmTriggerType.SHUNT_AREA_WHEEL_NO_SHUNT, false, area);
        eventCreater.createTriggerAlarm(AlarmTriggerType.SHUNT_AREA_WHEEL_NO_AVAILABLE, false, area);
        eventCreater.createTriggerAlarm(AlarmTriggerType.WHEEL_ALREADY_PACKING, false, area);
        setTagValue(area, false);
    }

    public String getInvNameByInvBasDoc(String invbasdoc) {
        LambdaQueryWrapper<PkBom> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PkBom::getPkInvbasdoc, invbasdoc);
        PkBom pkBom = pkBomMapper.selectOne(lambdaQueryWrapper);
        if (Objects.nonNull(pkBom)) {
            return pkBom.getInvname();
        }
        return "#";
    }

    public boolean checkActionStatus(int area) {
        LambdaQueryWrapper<PkAction> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PkAction::getArea, area);
        lambdaQueryWrapper.isNull(PkAction::getFinishTime);
        PkAction pkAction = pkActionMapper.selectOne(lambdaQueryWrapper);
        return Objects.isNull(pkAction);
    }
}
